using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;


namespace LabyrinthProject
{
    class Labyrinth : IDrawable
    {
        #region Fields
        private GraphicsDevice graphicsDevice;

        private Texture2D colorMapGround;
        private Texture2D normalMapGround;
        private Quad ground;

        private Texture2D colorMapWall;
        private Texture2D normalMapWall;

        private Texture2D doorColor;
        private Texture2D doorNormal;

        private Light shaderLight;
        private Material shaderMaterial;
        private Effect quadShaderEffect;

        private Texture2D labyrinthTexture;



        private System.Drawing.Bitmap labyrinthBmp;

        private int numberOfHorizontalWalls;
        private int numberOfVerticalWalls;
        private int numberOfHorizontalPaths;
        private int numberOfVerticalPaths;

        private int width;
        private int height;

        private List<WallElement> listOfWallElements;
        private List<PathElement> listOfPathElements;
        private List<Node> listOfNodeElements;
        #endregion

        #region Properties


        public int Width
        {
            get
            {
                return width;
            }
            set
            {
                width = value;
            }
        }
        public Texture2D LabyrinthTexture
        {
            get 
            { 
                return labyrinthTexture; 
            }
            set 
            { 
                labyrinthTexture = value; 
            }
        }
        public int Height
        {
            get
            {
                return height;
            }
            set
            {
                height = value;
            }
        }
        public List<Node> ListOfNodeElements
        {
            get
            {
                return listOfNodeElements;
            }
            set
            {
                listOfNodeElements = value;
            }
        }
        public List<PathElement> ListOfPathElements
        {
            get
            {
                return listOfPathElements;
            }
            set
            {
                listOfPathElements = value;
            }
        }
        public List<WallElement> ListOfWallElements
        {
            get
            {
                return listOfWallElements;
            }
            set
            {
                listOfWallElements = value;
            }
        }
        #endregion

        #region Methods
        public Labyrinth(GraphicsDevice graphicsDevice, int width, int height,
            Effect quadShaderEffect,
            Texture2D colorMapWall, Texture2D normalMapWall,
            Texture2D colorMapGround, Texture2D normalMapGround,
            Texture2D doorColor, Texture2D doorNormal)
        {
            this.graphicsDevice = graphicsDevice;

            LabyrinthGenerator labGen = new LabyrinthGenerator();
            Cell[,] maze = labGen.GenerateMaze(width / 2, height / 2);
            labyrinthBmp = labGen.GenerateTexture(maze, width / 2, height / 2);

            this.labyrinthTexture = getTexture2DFromBMP(labyrinthBmp);

            this.width = labyrinthBmp.Width;
            this.height = labyrinthBmp.Height;
            ground = new Quad(new Vector3((this.width-1) * 1000 / 2, 0, 0), Vector3.Up, Vector3.Forward, -(this.width - 1+6) * 1000, -(this.height - 1) * 1000);

            listOfWallElements = generateLabyrinthWalls(labyrinthBmp);
            listOfPathElements = generateLabyrinthPaths(labyrinthBmp);
            listOfNodeElements = generateLabyrinthNodes(listOfPathElements);

            createExitAndStartWalls(listOfWallElements);

            createVertexBufferForWalls();
            createVertexBufferForGround();
            generateNodeConnections();

            this.quadShaderEffect = quadShaderEffect;
            this.colorMapWall = colorMapWall;
            this.normalMapWall = normalMapWall;

            this.colorMapGround = colorMapGround;
            this.normalMapGround = normalMapGround;

            this.doorColor = doorColor;
            this.doorNormal = doorNormal;
        }

        private void createExitAndStartWalls(List<WallElement> listOfWallElements)
        {
            WallElement wallElement;
            int ypos = width / 2 - 1;


            listOfWallElements.RemoveAt(numberOfHorizontalWalls + numberOfVerticalWalls - 1);

            wallElement = new WallElement(new Vector2(width - 1, ypos + 3), new Vector2(width - 1, height-1));
            listOfWallElements.Add(wallElement);

            wallElement = new WallElement(new Vector2(width - 1, 0), new Vector2(width - 1, ypos));
            listOfWallElements.Add(wallElement);
            



            listOfWallElements.RemoveAt(numberOfHorizontalWalls);

            wallElement = new WallElement(new Vector2(0, ypos + 3), new Vector2(0, height-1));
            listOfWallElements.Add(wallElement);

            wallElement = new WallElement(new Vector2(0, 0), new Vector2(0, ypos));
            listOfWallElements.Add(wallElement);





            wallElement = new WallElement(new Vector2(-3, ypos), new Vector2(0 - wallElement.WallWide, ypos));
            listOfWallElements.Add(wallElement);

            wallElement = new WallElement(new Vector2(-3, ypos + 3), new Vector2(0 - wallElement.WallWide, ypos + 3));
            listOfWallElements.Add(wallElement);

            wallElement = new WallElement(new Vector2(-3, ypos) , new Vector2(-3, ypos + 3));
            listOfWallElements.Add(wallElement);




            wallElement = new WallElement(new Vector2(width - 1 + wallElement.WallWide, ypos), new Vector2(width + 3 - 1, ypos));
            listOfWallElements.Add(wallElement);

            wallElement = new WallElement(new Vector2(width - 1 + wallElement.WallWide, ypos + 3), new Vector2(width + 3 - 1, ypos + 3));
            listOfWallElements.Add(wallElement);

            wallElement = new WallElement(new Vector2(width + 3-1, ypos), new Vector2(width+3-1, ypos + 3));
            listOfWallElements.Add(wallElement);



            //izlaz
            wallElement = new WallElement(new Vector2(width - 1, ypos + wallElement.WallWide), new Vector2(width - 1, ypos + 3 - wallElement.WallWide), WalllType.exitWallSegment);
            listOfWallElements.Add(wallElement);

            //ulaz
            wallElement = new WallElement(new Vector2(0, ypos + wallElement.WallWide), new Vector2(0, ypos + 3  - wallElement.WallWide), WalllType.startWallSegment);
            listOfWallElements.Add(wallElement);


     

        }

        private Texture2D getTexture2DFromBMP(System.Drawing.Bitmap bitmap)
        {
            Texture2D texture2D = new Texture2D(LabyrinthGame.GDevice, bitmap.Width, bitmap.Height, false, SurfaceFormat.Color);

            // Lock the bitmap data

            System.Drawing.Imaging.BitmapData data = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, bitmap.PixelFormat);

            // calculate the byte size: for PixelFormat.Format32bppArgb (standard for GDI bitmaps) it's the hight * stride
            int bufferSize = data.Height * data.Stride; // stride already incorporates 4 bytes per pixel

            // create buffer
            byte[] bytes = new byte[bufferSize];


            // copy bitmap data into buffer
            System.Runtime.InteropServices.Marshal.Copy(data.Scan0, bytes, 0, bytes.Length);

            // copy our buffer to the texture
            texture2D.SetData(bytes);

            // unlock the bitmap data
            bitmap.UnlockBits(data);

            return texture2D;
        }

        public void Draw(Camera camera)
        {
            setShaderValues(camera);

            // Bind the texture maps to the shader.
            quadShaderEffect.Parameters["colorMapTexture"].SetValue(colorMapGround);
            quadShaderEffect.Parameters["normalMapTexture"].SetValue(normalMapGround);

            drawQuadElement(ground);

            // Bind the texture maps to the shader.
            quadShaderEffect.Parameters["colorMapTexture"].SetValue(colorMapWall);
            quadShaderEffect.Parameters["normalMapTexture"].SetValue(normalMapWall);

            foreach (WallElement wall in listOfWallElements)
            {
                if (wall.WallType != WalllType.normalWallSegment)
                {
                    quadShaderEffect.Parameters["colorMapTexture"].SetValue(doorColor);
                    quadShaderEffect.Parameters["normalMapTexture"].SetValue(doorNormal);

                    LabyrinthGame.GDevice.BlendState = BlendState.AlphaBlend;

                    drawQuadElement(wall.LeftQuad);
                    drawQuadElement(wall.RightQuad);

                    continue;
                }

                drawQuadElement(wall.BeginQuad);
                drawQuadElement(wall.EndQuad);
                drawQuadElement(wall.LeftQuad);
                drawQuadElement(wall.RightQuad);
                drawQuadElement(wall.TopQuad);
            }

        }

 

        private void drawQuadElement(Quad quad)
        {
            graphicsDevice.SetVertexBuffer(quad.VertexBuffer);

            foreach (EffectPass pass in quadShaderEffect.CurrentTechnique.Passes)
            {
                pass.Apply();
                graphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 2);
            }
        }
        private void setShaderValues(Camera camera)
        {
            // Initialize light settings.
            // Directional lighting is the default.
            Color globalAmbient = new Color(new Vector4(0.2f, 0.2f, 0.2f, 1.0f));
            shaderLight.Type = Light.LightType.DirectionalLight;
            shaderLight.Direction = camera.ChasePosition - camera.Position;
            shaderLight.Direction.Normalize();
            shaderLight.Position = camera.LookAtOffset;
            shaderLight.Ambient = Color.White;
            shaderLight.Diffuse = Color.White;
            shaderLight.Specular = Color.White;
            shaderLight.SpotInnerConeRadians = MathHelper.ToRadians(20.0f);
            shaderLight.SpotOuterConeRadians = MathHelper.ToRadians(30.0f);
            shaderLight.Radius = 10.0f;

            // Initialize material settings.
            shaderMaterial.Ambient = new Color(new Vector4(0.3f, 0.3f, 0.3f, 1f));
            shaderMaterial.Diffuse = new Color(new Vector4(0.5f, 0.5f, 0.5f, 1.0f));
            shaderMaterial.Emissive = new Color(new Vector4(0.2f, 0.2f, 0.2f, 1.0f));
            shaderMaterial.Specular = new Color(new Vector4(0.2f, 0.2f, 0.2f, 1.0f));
            shaderMaterial.Shininess = 2f;

            // Calculate the view matrix.
            Matrix view = camera.View;

            // Calculate the world matrix.
            Matrix world = Matrix.Identity;

            // Calculate the transposed inverse of the world matrix.
            Matrix worldInvTrans = Matrix.Transpose(Matrix.Invert(world));

            // Calculate combined world-view-projection matrix.
            Matrix worldViewProj = world * view * camera.Projection;

            // Set shader matrix parameters.
            quadShaderEffect.Parameters["worldMatrix"].SetValue(world);
            quadShaderEffect.Parameters["worldInverseTransposeMatrix"].SetValue(worldInvTrans);
            quadShaderEffect.Parameters["worldViewProjectionMatrix"].SetValue(worldViewProj);

            // Set the shader camera position parameter.
            quadShaderEffect.Parameters["cameraPos"].SetValue(camera.Position);

            // Set the shader global ambiance parameters.
            quadShaderEffect.Parameters["globalAmbient"].SetValue(globalAmbient.ToVector4());
           
            // Set the shader lighting parameters.
            quadShaderEffect.Parameters["light"].StructureMembers["dir"].SetValue(shaderLight.Direction);
            quadShaderEffect.Parameters["light"].StructureMembers["pos"].SetValue(shaderLight.Position);
            quadShaderEffect.Parameters["light"].StructureMembers["ambient"].SetValue(shaderLight.Ambient.ToVector4());
            quadShaderEffect.Parameters["light"].StructureMembers["diffuse"].SetValue(shaderLight.Diffuse.ToVector4());
            quadShaderEffect.Parameters["light"].StructureMembers["specular"].SetValue(shaderLight.Specular.ToVector4());
            quadShaderEffect.Parameters["light"].StructureMembers["spotInnerCone"].SetValue(shaderLight.SpotInnerConeRadians);
            quadShaderEffect.Parameters["light"].StructureMembers["spotOuterCone"].SetValue(shaderLight.SpotOuterConeRadians);
            quadShaderEffect.Parameters["light"].StructureMembers["radius"].SetValue(shaderLight.Radius);

            //// Set the shader material parameters.
            quadShaderEffect.Parameters["material"].StructureMembers["ambient"].SetValue(shaderMaterial.Ambient.ToVector4());
            quadShaderEffect.Parameters["material"].StructureMembers["diffuse"].SetValue(shaderMaterial.Diffuse.ToVector4());
            quadShaderEffect.Parameters["material"].StructureMembers["emissive"].SetValue(shaderMaterial.Emissive.ToVector4());
            quadShaderEffect.Parameters["material"].StructureMembers["specular"].SetValue(shaderMaterial.Specular.ToVector4());
            quadShaderEffect.Parameters["material"].StructureMembers["shininess"].SetValue(shaderMaterial.Shininess);
        }

        private void createVertexBufferForWalls()
        {
            VertexDeclaration vertexDecl = new VertexDeclaration(NormalMappedVertex.VertexElements);

            foreach (WallElement wall in listOfWallElements)
            {

                wall.BeginQuad.VertexBuffer = new VertexBuffer(graphicsDevice, vertexDecl, NormalMappedVertex.SizeInBytes * wall.BeginQuad.Vertices.Length, BufferUsage.WriteOnly);
                wall.BeginQuad.VertexBuffer.SetData<NormalMappedVertex>(wall.BeginQuad.Vertices);

                wall.EndQuad.VertexBuffer = new VertexBuffer(graphicsDevice, vertexDecl, NormalMappedVertex.SizeInBytes * wall.EndQuad.Vertices.Length, BufferUsage.WriteOnly);
                wall.EndQuad.VertexBuffer.SetData<NormalMappedVertex>(wall.EndQuad.Vertices);

                wall.LeftQuad.VertexBuffer = new VertexBuffer(graphicsDevice, vertexDecl, NormalMappedVertex.SizeInBytes * wall.LeftQuad.Vertices.Length, BufferUsage.WriteOnly);
                wall.LeftQuad.VertexBuffer.SetData<NormalMappedVertex>(wall.LeftQuad.Vertices);

                wall.RightQuad.VertexBuffer = new VertexBuffer(graphicsDevice, vertexDecl, NormalMappedVertex.SizeInBytes * wall.RightQuad.Vertices.Length, BufferUsage.WriteOnly);
                wall.RightQuad.VertexBuffer.SetData<NormalMappedVertex>(wall.RightQuad.Vertices);

                wall.TopQuad.VertexBuffer = new VertexBuffer(graphicsDevice, vertexDecl, NormalMappedVertex.SizeInBytes * wall.TopQuad.Vertices.Length, BufferUsage.WriteOnly);
                wall.TopQuad.VertexBuffer.SetData<NormalMappedVertex>(wall.TopQuad.Vertices);
            }
        }
        private void createVertexBufferForGround()
        {
            VertexDeclaration vertexDecl = new VertexDeclaration(NormalMappedVertex.VertexElements);
            ground.VertexBuffer = new VertexBuffer(graphicsDevice, vertexDecl, NormalMappedVertex.SizeInBytes * ground.Vertices.Length, BufferUsage.WriteOnly);
            ground.VertexBuffer.SetData<NormalMappedVertex>(ground.Vertices);
        }

        private void generateNodeConnections()
        {
            foreach (Node node in listOfNodeElements)
            {
                node.LeftNode = findLeftNode(node);
                node.RightNode = findRightNode(node);
                node.TopNode = findTopNode(node);
                node.BottomNode = findBottomNode(node);

            }
        }

        private Node findBottomNode(Node firstNode)
        {
            Node firstNeighBor = null;

            foreach (Node secondNode in listOfNodeElements)
            {
                if (firstNode == secondNode)
                    continue;

                if (secondNode.VerticalPathElement != null && firstNode.VerticalPathElement != null && secondNode.VerticalPathElement == firstNode.VerticalPathElement)
                {
                    if (secondNode.Position.Y > firstNode.Position.Y)
                    {
                        if (firstNeighBor != null)
                        {
                            if (firstNeighBor.Position.Y < secondNode.Position.Y)
                            {
                                continue;
                            }
                            else
                            {
                                firstNeighBor = secondNode;
                            }
                        }
                        else
                        {
                            firstNeighBor = secondNode;
                        }
                    }
                }
            }


            return firstNeighBor;
        }
        private Node findTopNode(Node firstNode)
        {
            Node firstNeighBor = null;

            foreach (Node secondNode in listOfNodeElements)
            {
                if (firstNode == secondNode)
                    continue;

                if (secondNode.VerticalPathElement != null && firstNode.VerticalPathElement != null && secondNode.VerticalPathElement == firstNode.VerticalPathElement)
                {
                    if (secondNode.Position.Y < firstNode.Position.Y)
                    {
                        if (firstNeighBor != null)
                        {
                            if (firstNeighBor.Position.Y > secondNode.Position.Y)
                            {
                                continue;
                            }
                            else
                            {
                                firstNeighBor = secondNode;
                            }
                        }
                        else
                        {
                            firstNeighBor = secondNode;
                        }
                    }
                }
            }


            return firstNeighBor;
        }
        private Node findRightNode(Node firstNode)
        {
            Node firstNeighBor = null;

            foreach (Node secondNode in listOfNodeElements)
            {
                if (firstNode == secondNode)
                    continue;

                if (secondNode.HorizontalPathElement != null && firstNode.HorizontalPathElement != null && secondNode.HorizontalPathElement == firstNode.HorizontalPathElement)
                {
                    if (secondNode.Position.X > firstNode.Position.X)
                    {
                        if (firstNeighBor != null)
                        {
                            if (firstNeighBor.Position.X < secondNode.Position.X)
                            {
                                continue;
                            }
                            else
                            {
                                firstNeighBor = secondNode;
                            }
                        }
                        else
                        {
                            firstNeighBor = secondNode;
                        }
                    }
                }
            }


            return firstNeighBor;
        }
        private Node findLeftNode(Node firstNode)
        {
            Node firstNeighBor = null;

            foreach (Node secondNode in listOfNodeElements)
            {
                if (firstNode == secondNode)
                    continue;

                if (secondNode.HorizontalPathElement != null && firstNode.HorizontalPathElement != null && secondNode.HorizontalPathElement == firstNode.HorizontalPathElement)
                {
                    if (secondNode.Position.X < firstNode.Position.X)
                    {
                        if (firstNeighBor != null)
                        {
                            if (firstNeighBor.Position.X > secondNode.Position.X)
                            {
                                continue;
                            }
                            else
                            {
                                firstNeighBor = secondNode;
                            }
                        }
                        else
                        {
                            firstNeighBor = secondNode;
                        }
                    }
                }
            }


            return firstNeighBor;

        }

        private List<Node> generateLabyrinthNodes(List<PathElement> listOfPathElements)
        {
            List<Node> listOfNodeElements = new List<Node>();

            //kreiraj cvorove

            for (int i = 0; i < numberOfHorizontalPaths; i++)
            {
                for (int j = numberOfHorizontalPaths; j < numberOfHorizontalPaths + numberOfVerticalPaths; j++)
                {
                    Vector2 nodePosition = getPathsIntersection(listOfPathElements[i], listOfPathElements[j]);

                    if (nodePosition != new Vector2())
                    {
                        listOfNodeElements.Add(new Node(nodePosition, listOfPathElements[i], listOfPathElements[j]));
                    }
                }
            }

            foreach (PathElement path in listOfPathElements)
            {
                bool beginExists = false;
                bool endExists = false;
                foreach (Node node in listOfNodeElements)
                {
                    if (path.Beginig == node.Position)
                    {
                        beginExists = true;
                        if (beginExists && endExists)
                            break;
                    }

                    if (path.End == node.Position)
                    {
                        endExists = true;
                        if (beginExists && endExists)
                            break;
                    }
                }

                if (!beginExists)
                {
                    if (path.Beginig.X == path.End.X)//hor
                    {
                        listOfNodeElements.Add(new Node(path.Beginig, null, path));
                    }
                    else if (path.Beginig.Y == path.End.Y)//ver
                    {
                        listOfNodeElements.Add(new Node(path.Beginig, path, null));
                    }
                }

                if (!endExists)
                {
                    if (path.Beginig.X == path.End.X)//hor
                    {
                        listOfNodeElements.Add(new Node(path.End, null, path));
                    }
                    else if (path.Beginig.Y == path.End.Y)//ver
                    {
                        listOfNodeElements.Add(new Node(path.End, path, null));
                    }
                }
            }




            return listOfNodeElements;
        }
        private Vector2 getPathsIntersection(PathElement horPathElement, PathElement verPathElement)
        {
            Vector2 intersection = new Vector2();


            if (horPathElement.Beginig.X <= verPathElement.Beginig.X && horPathElement.End.X >= verPathElement.Beginig.X &&
                verPathElement.Beginig.Y <= horPathElement.Beginig.Y && verPathElement.End.Y >= horPathElement.Beginig.Y)
            {

                intersection = new Vector2(verPathElement.Beginig.X, horPathElement.Beginig.Y);
            }

            return intersection;
        }
        private List<WallElement> generateLabyrinthWalls(System.Drawing.Bitmap bmp)
        {
            List<WallElement> listOfWallElements = new List<WallElement>();

            for (int y = 0; y < bmp.Height; y++)
            {
                int startIndex = -1;
                int endIndex = -1;

                for (int x = 0; x < bmp.Width; x++)
                {
                    if (bmp.GetPixel(x, y).B == 0 && startIndex == -1)
                    {
                        startIndex = x;
                    }
                    else if (bmp.GetPixel(x, y).B == 0 && startIndex != -1)
                    {
                        endIndex = x;

                        if (x == bmp.Width - 1)
                        {
                            WallElement wallElement = new WallElement(new Vector2(startIndex, y), new Vector2(endIndex, y));
                            listOfWallElements.Add(wallElement);

                            startIndex = -1;
                            endIndex = -1;
                        }

                    }
                    else if (bmp.GetPixel(x, y).B != 0 && startIndex != -1 && endIndex == -1)
                    {
                        startIndex = -1;
                    }
                    else if ((bmp.GetPixel(x, y).B != 0 && startIndex != -1 && endIndex != -1))
                    {
                        WallElement wallElement = new WallElement(new Vector2(startIndex, y), new Vector2(endIndex, y));
                        listOfWallElements.Add(wallElement);

                        startIndex = -1;
                        endIndex = -1;
                    }

                }
            }

            numberOfHorizontalWalls = listOfWallElements.Count();
            //treba napravit da je u istom pozivu...

            for (int x = 0; x < bmp.Width; x++)
            {
                int startIndex = -1;
                int endIndex = -1;

                for (int y = 0; y < bmp.Height; y++)
                {
                    if (bmp.GetPixel(x, y).B == 0 && startIndex == -1)
                    {
                        startIndex = y;
                    }
                    else if (bmp.GetPixel(x, y).B == 0 && startIndex != -1)
                    {
                        endIndex = y;


                        if (y == bmp.Height - 1)
                        {
                            WallElement wallElement = new WallElement(new Vector2(x, startIndex), new Vector2(x, endIndex));
                            listOfWallElements.Add(wallElement);

                            startIndex = -1;
                            endIndex = -1;
                        }

                    }
                    else if (bmp.GetPixel(x, y).B != 0 && startIndex != -1 && endIndex == -1)
                    {
                        startIndex = -1;
                    }
                    else if (bmp.GetPixel(x, y).B != 0 && startIndex != -1 && endIndex != -1)
                    {
                        WallElement wallElement = new WallElement(new Vector2(x, startIndex), new Vector2(x, endIndex));
                        listOfWallElements.Add(wallElement);

                        startIndex = -1;
                        endIndex = -1;
                    }

                }
            }

            numberOfVerticalWalls = listOfWallElements.Count() - numberOfHorizontalWalls;

            return listOfWallElements;
        }
        private List<PathElement> generateLabyrinthPaths(System.Drawing.Bitmap bmp)
        {
            List<PathElement> listOfPathElements = new List<PathElement>();

            for (int y = 0; y < bmp.Height; y++)
            {
                int startIndex = -1;
                int endIndex = -1;

                for (int x = 0; x < bmp.Width; x++)
                {
                    if (bmp.GetPixel(x, y).B == 255 && startIndex == -1)
                    {
                        startIndex = x;
                    }
                    else if (bmp.GetPixel(x, y).B == 255 && startIndex != -1)
                    {
                        endIndex = x;

                        if (x == bmp.Width - 1)
                        {
                            PathElement pathElement = new PathElement(new Vector2(startIndex, y), new Vector2(endIndex, y));
                            listOfPathElements.Add(pathElement);

                            startIndex = -1;
                            endIndex = -1;
                        }

                    }
                    else if (bmp.GetPixel(x, y).B != 255 && startIndex != -1 && endIndex == -1)
                    {
                        startIndex = -1;
                    }
                    else if ((bmp.GetPixel(x, y).B != 255 && startIndex != -1 && endIndex != -1))
                    {
                        PathElement pathElement = new PathElement(new Vector2(startIndex, y), new Vector2(endIndex, y));
                        listOfPathElements.Add(pathElement);

                        startIndex = -1;
                        endIndex = -1;
                    }

                }
            }

            numberOfHorizontalPaths = listOfPathElements.Count();

            for (int x = 0; x < bmp.Width; x++)
            {
                int startIndex = -1;
                int endIndex = -1;

                for (int y = 0; y < bmp.Height; y++)
                {
                    if (bmp.GetPixel(x, y).B == 255 && startIndex == -1)
                    {
                        startIndex = y;
                    }
                    else if (bmp.GetPixel(x, y).B == 255 && startIndex != -1)
                    {
                        endIndex = y;


                        if (y == bmp.Height - 1)
                        {
                            PathElement pathElement = new PathElement(new Vector2(x, startIndex), new Vector2(x, endIndex));
                            listOfPathElements.Add(pathElement);

                            startIndex = -1;
                            endIndex = -1;
                        }

                    }
                    else if (bmp.GetPixel(x, y).B != 255 && startIndex != -1 && endIndex == -1)
                    {
                        startIndex = -1;
                    }
                    else if (bmp.GetPixel(x, y).B != 255 && startIndex != -1 && endIndex != -1)
                    {
                        PathElement pathElement = new PathElement(new Vector2(x, startIndex), new Vector2(x, endIndex));
                        listOfPathElements.Add(pathElement);

                        startIndex = -1;
                        endIndex = -1;
                    }

                }
            }

            numberOfVerticalPaths = listOfPathElements.Count() - numberOfHorizontalPaths;

            return listOfPathElements;
        }

        #endregion
    }
}